import time, os, selectors
from socket import *

BASE_DIR = os.path.dirname(os.path.abspath(__file__))


class Server:
    def __init__(self):
        self.ip_port = ("127.0.0.1", 8001)
        self.sel = selectors.DefaultSelector()  # 根据平台选择最佳的IO多路机制，比如linux就会选择epoll

        self.dic = {}
        self.create_sock()
        self.handle()

    def create_sock(self):
        sk = socket(AF_INET, SOCK_STREAM)
        sk.bind((self.ip_port))
        sk.setblocking(False)
        sk.listen(5)
        self.sel.register(sk, selectors.EVENT_READ, self.accept)  # 注册监听对象

    def handle(self):
        while True:
            events = self.sel.select()  ##监听谁发生变化了

            for key, mask in events:
                func = key.data  # 获取对象调用的函数
                func(key.fileobj, mask)

    def accept(self, sock, mask):
        print("登录服务端")
        conn, addr = sock.accept()
        # data = conn.recv(1024)
        self.sel.register(conn, selectors.EVENT_READ, self.read)
        self.dic[conn] = {}

    def read(self, conn, mask):
        try:
            if not self.dic[conn]:

                data = conn.recv(1024)
                try:
                    cmd, filename, filesize = str(data.decode("utf-8")).split("|")
                    self.dic[conn] = {"cmd": cmd, "filename": filename, "filesize": filesize, "hasReceived": 0}
                except Exception as e:
                    cmd, filename = str(data.decode("utf-8")).split("|")
                    self.dic[conn] = {"cmd": cmd, "filename": filename,
                                      "filesize": os.path.getsize(os.path.join(BASE_DIR, "load", filename)),
                                      "hasSended": 0}

                if cmd == "put":  # 上传
                    conn.send("ok".encode("utf-8"))
                if cmd == "get":  # 下载
                    conn.send(str(self.dic[conn]["filesize"]).encode("utf-8"))


            else:

                if self.dic[conn].get("cmd", None):

                    cmd = self.dic[conn].get("cmd")
                    if hasattr(self, cmd):
                        func = getattr(self, cmd)
                        func(conn, mask)
                    else:
                        print("error")
        except Exception as e:
            print(e)
            print(conn, "断开连接")
            conn.close()
            self.sel.unregister(conn)

    def put(self, conn, mask):

        filename = self.dic[conn]['filename']
        filesize = self.dic[conn]['filesize']

        path = os.path.join(BASE_DIR, "upload", filename)
        data = conn.recv(1024)
        conn.send("success".encode("utf-8"))
        self.dic[conn]['hasReceived'] += len(data)
        with open(path, "ab") as f:
            f.write(data)
        if self.dic[conn]['hasReceived'] == self.dic[conn]['filesize']:
            self.dic[conn] = {}
            print("上传结束")

    def get(self, conn, mask):

        filename = self.dic[conn]['filename']
        path = os.path.join(BASE_DIR, "load", filename)

        with open(path, "rb") as f:
            f.seek(self.dic[conn]["hasSended"], 0)
            data = f.read(10)
            conn.send(data)
            self.dic[conn]['hasSended'] += len(data)
            if self.dic[conn]['hasSended'] == self.dic[conn]["filesize"]:
                self.dic[conn] = {}
                print("下载结束")
        time.sleep(0.5)


if __name__ == "__main__":
    Server()